<?php

namespace App\Third\Acsign;

use GuzzleHttp;
use Mjy191\Tools\Tools;

class Acsing
{
    private $appId;
    private $apiSecret;
    private $domian;
    private $url;
    private $data;

    public function __construct(){
        $this->appId = config('acsign.appId');
        $this->apiSecret = config('acsign.apiSecret');
        $this->domian = config('acsign.domian');
    }

    /**
     * 个人实名认证网页版
     * @param $user
     * @return array
     */
    public function authCompanyIdentifyUrl()
    {
        $this->url = '/auth/company/identifyUrl';
        $this->data = [
            'authTypeList' => [],
            'companyAuthTypeList' => [],
            'companyName' => '',
            'creditCode' => '',
            'legalPersonName' => '',
            'legalPersonIdCardNo' => '',
            'agentName' => '',
            'agentIdCardNo' => '',
            'immutableInfoList' => [],
            'redirectUrl' => '',
            'notifyUrl' => 'http://yunapi.moudian520.com/agency/agencyAuthNotify',
            'bizId' => '',
            'faceAuthMode' => 2,
            'showResult' => 1,
            'mobileRequired' => 0,
            'isIframe' => 0,
            'isNotice' => 0,
            'noticeMobile' => '',
            'needSignPwd' => 0,
        ];
        return $this->request();
    }

    /**
     * 查询实名认证详细信息。
     * @return array
     */
    public function getAuthRecordInfo($params)
    {
        $this->url = '/auth/getAuthRecordInfo';
        $this->data = [
            'serialNo' => $params['serialNo']
        ];
        return $this->request();
    }

    /**
     * @author: Neupres·lin
     * @name: uploadTemplate
     * @description: 新增/编辑模板
     * @param {*}String $templateName 模板编号
     * @return {*}
     */
    public function openTemplate($params)
    {
        $this->url = '/template/open';
        $this->data = [
            'templateIdent' => $params['templateid'],
            'redirectUrl' => config('filesystems.domain') . '/#/setting/sysConfig/contracttemp',
            'notifyUrl' => Tools::getHost() . '/api/signnotify',
            'hiddenBasic' => 1,
            'isControlDelete' => 1,
            'controlData' => $params['controldata']
        ];

        return $this->request();
    }

    /**
     * @author: Neupres·lin
     * @name: uploadTemplate
     * @description: 同步模板
     * @param {*}String $templateName 模板编号
     * @return {*}
     */
    public function syncTemplate($params)
    {
        $this->url = '/template/sync';
        $this->data = [
            'templateIdent' => $params['templateident'],
        ];

        return $this->request();
    }

    /**
     * @author: Neupres·lin
     * @name: uploadTemplate
     * @description: 撤销模板
     * @param {*}String $templateName 模板编号
     * @return {*}
     */
    public function cancelTemplate($params)
    {
        $this->url = '/template/sync/cancel';
        $this->data = [
            'templateIdent' => $params['templateident'],
        ];

        return $this->request();
    }

    /**
     * @author: Neupres·lin
     * @name: uploadTemplate
     * @description: 删除模板
     * @param {*}String $templateName 模板编号
     * @return {*}
     */
    public function deleteTemplate($params)
    {
        $this->url = '/template/delete';
        $this->data = [
            'templateIdent' => $params['templateident'],
        ];

        return $this->request();
    }

    /**
     * @author: Neupres·lin
     * @name: uploadTemplate
     * @description: 获取模板填充信息
     * @param {*}String $templateName 模板编号
     * @return {*}
     */
    public function getTemplateData($templateident)
    {
        $this->url = '/template/data';
        $this->data = [
            'templateIdent' => $templateident,
        ];

        return $this->request();
    }

    /**
     * @author: Neupres·lin
     * @name: uploadTemplate
     * @description: 查询模板列表
     * @param {*}String $templateName 模板编号
     * @return {*}
     */
    public function getTemplateList($templateident)
    {
        $this->url = '/template/list';
        $this->data = [
            'templateIdent' => $templateident,
        ];

        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: saveReq
     * @description: api请求完成后回调的函数
     * @param {*} $url
     * @param {*} $data
     * @param {*} $postFields
     * @param {*} $resData
     * @param {*} $code
     * @param {*} $msg
     * @return {*}
     */
    public function saveReq($url, $data, $postFields, $resData, $code, $msg){

    }
//---------------------------------------------------------------------------------------用户类型接口
//              企业或个人签署电子合同人->对应用户 主键account
//---------------------------------------------------------------------------------------
    /**
     * @author: Neupres·lin
     * @name: addPersonalUser
     * @description: 添加个人用户
     * @param {*}String $account 用户唯一识别码(可以使用证件号手机号等标识)
     * @param {*}String $realName 用户真实姓名
     * @param {*}String $idCard 证件号
     * @param {*}String $idCardType 证件类型默认1居民身份证 2台湾居民来往内地通行证 3港澳居民往来内地通行证
     * @param {*}String $mobile 手机号 用于接收短信验证码
     * @param {}String $isSignPwdNotice 是否短信通知签署密码 0:不通知 1：通知
     * @param {}int $identifyType 添加用户实名认证方法   1身份证两要素 姓名身份证  2运营商三要素认证 姓名身份证手机号 3银行卡四要素 姓名身份证手机号银行卡号
     * @param {}String $identifyMobile 认证使用手机号
     * @param {}String $bankCard 认证使用银行账号，银行卡四要素使用
     * @param {}String $isNotice 开启短信通知 用户发起合同时和需要发送签署密码通知时 0：否(默认) 1：是
     * @return {}
     */
    // $adduser = $this->ACsign->addPersonalUser("13929792521","孙民华","330702197108020812","1","13929792521","0","",1,"","","");
    public function addPersonalUser($account,$name,$idCard,$idCardType,$mobile,$isSignPwdNotice,$signPwd,$identifyType=1,$identifyMobile,$bankCard,$isNotice){
        $this->url = '/user/addPersonalUser';
        $this->data = [
            "account" => $account,
            "name" => $name,
            "idCard" => $idCard,
            "idCardType" => $idCardType,
            "mobile" => $mobile,
            "isSignPwdNotice" => $isSignPwdNotice,
            "signPwd" => $signPwd,
            "identifyType" => $identifyType,
            "identifyMobile" => $identifyMobile,
            "bankCard" => $bankCard,
            "isNotice" => $isNotice,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: addEnterpriseUser
     * @description: 添加企业用户
     * @param {*}String $account 个人身份证号邮箱，手机号等，唯一标识
     * @param {*}String $companyName 企业名称
     * @param {*}String $creditCode 企业社会统一信用代码
     * @param {*}String $name 法人姓名
     * @param {*}String $idCard 法人身份证号
     * @param {}String $identifyMobile 法人手机号（需是本人实名登记的）
     * @param {}String $isSignPwdNotice （是否将签署密码以短信的方式发送给用户）0:不通知（默认） 1：通知
     * @param {}String $isNotice 开启短信通知(用户发起合同时和需要发送签署密码通知时), 0：否(默认) 1：是
     * @param {}String $signPwd 如果不填，则由系统随机生成6位签署密码
     * @param {*}String $mobile 该手机号将用于企业用户合同签署，请确保真实有效（用于短信验证码接收）
     * @param {*}String $contactName 联系人姓名
     * @param {*}String $contactIdCard 联系人身份证号
     * @param {}Int $identifyType 法人实名认证类型:1：法人银行卡四要素认证（仅限银联卡）3：法人运营商手机三要素认证
     * @param {}String $bankCard 认证使用银行账号，银行卡四要素认证时使用
     * @return {*}
     */
    public function addEnterpriseUser($account,$companyName,$creditCode,$name,$idCard,$identifyMobile,$mobile,$contactName,$contactIdCard,$identifyType=1){
        $this->url = '/user/addEnterpriseUser';
        $this->data = [
            'account'         => $account,
            'companyName'     => $companyName,
            'creditCode'      => $creditCode,
            'name'            => $name,
            'idCard'          => $idCard,
            'identifyMobile'  => $identifyMobile,
            'mobile'          => $mobile,
            'contactName'     => $contactName,
            'contactIdCard'   => $contactIdCard,
            'identifyType'    => $identifyType
        ];

        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: getUser
     * @description: 查询用户
     * @param {*}String $account 用户唯一识别码
     * @return {*}
     */
    // $adduser = $this->ACsign->getUser("16621251415");
    public function getUser($account){
        $this->url = '/user/getUser';
        $this->data = [
            'account' => $account,
        ];
        return $this->request();
    }

    /**
     * @author: Neupres·lin
     * @name: getUser
     * @description: 查询企业信息
     * @param {*}String $account 用户唯一识别码
     * @return {*}
     */
    public function getCompUser($account){
        $this->url = '/user/getCompUser';
        $this->data = [
            'account' => $account,
        ];
        return $this->request();
    }

    /**
     * @author: Neupres·lin
     * @name: modifyMobileByCode
     * @description: 修改用户绑定手机号（验证码方式）
     * @param {*}String $account 唯一识别码
     * @param {*}String $mobile 用户修改后绑定手机号码
     * @param {*}String $code 用户原手机号接收验证码
     * @param {*}String $codeToken 提交用户信息接口回传token
     * @return {*}
     */
    public function modifyMobileByCode($account,$mobile,$code,$codeToken){
        $this->url = '/user/modifyMobileByCode';
        $this->data = [
            'account'   => $account,
            'mobile'    => $mobile,
            'code'      => $code,
            'codeToken' => $codeToken,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: sendCode
     * @description: 发送验证码（修改用户绑定手机号）
     * @param {*}String $account 用户唯一识别码
     * @return {*}
     */
    // $adduser = $this->ACsign->sendCode("13929792521");
    public function sendCode($account){
        $this->url = '/user/sendCode';
        $this->data = [
            'account'   => $account,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: modifyMobile
     * @description: 修改手机号（运营商三要素一致性验证） 通过验证姓名 身份证 手机号修改
     * @param {*}String $account 用户唯一识别码
     * @param {*}String $name 姓名
     * @param {*}String $idCard 个人身份证号
     * @param {*}String $mobile 用户修改后绑定手机号码
     * @return {*}
     */
    public function modifyMobile($account,$name,$idCard,$mobile){
        $this->url = '/user/modifyMobile';
        $this->data = [
            'account' => $account,
            'name'    => $name,
            'idCard'  => $idCard,
            'mobile'  => $mobile,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: updateMobile
     * @description: 修改手机号（无需运营商认证）
     * @param {*}String $account 用户唯一识别码
     * @param {*}String $idCard 个人身份证号
     * @param {*}String $mobile 用户修改后绑定手机号码
     * @return {*}
     */
    public function updateMobile($account,$idCard,$mobile){
        $this->url = '/user/updateMobile';
        $this->data = [
            'account' => $account,
            'idCard'  => $idCard,
            'mobile'  => $mobile,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: signPasswd
     * @description: 修改签约密码
     * @param {*}String $account 唯一识别码
     * @param {*}String $oldSignPwd 修改前的签署密码
     * @param {*}String $signPwd 修改后的签署密码
     * @return {*}
     */
    public function signPasswd($account,$oldSignPwd,$signPwd){
        $this->url = '/user/signPasswd';
        $this->data = [
            'account'    => $account,
            'oldSignPwd' => $oldSignPwd,
            'signPwd'    => $signPwd,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: startModSignPasswd
     * @description: 初始化签署密码
     * @param {*}String $account 唯一识别码
     * @return {*}
     */
    public function startModSignPasswd($account){
        $this->url = '/user/startModSignPasswd';
        $this->data = [
            'account'   => $account,
        ];
        return $this->request();
    }
//---------------------------------------------------------------------------------------用章类型接口
//                    所属用章列表 主键sealNo->对应用户 主键account
//---------------------------------------------------------------------------------------
    /**
     * @author: Neupres·lin
     * @name: createSeal
     * @description: 创建印章
     * @param {*}String $account 用户唯一识别码
     * @param {}MultipartFile $image 图片信息
     * @param {*}String $isDefault 是否默认签，0：否 1：是
     * @param {*}String $sealName 印章名称 (60个字符以内)
     * @param {*}String $sealNo 印章编号 (32个字符)
     * @param {}float $scaling 图片缩放百分比 (介于0~1之间的数字)
     * @return {*}
     */
    public function createSeal($account,$image,$isDefault=0,$sealName,$sealNo,$scaling){
        $this->url = '/user/createSeal';
        $this->data = [
            'account'   => $account,
            'image'     => $image,
            'isDefault' => $isDefault,
            'sealName'  => $sealName,
            'sealNo'    => $sealNo,
            'scaling'   => $scaling,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: modifySeal
     * @description: 修改印章
     * @param {*}String $account 用户唯一识别码
     * @param {}MultipartFile $image 图片信息
     * @param {*}String $isDefault 是否默认签，0：否 1：是
     * @param {*}String $sealName 印章名称 (60个字符以内)
     * @param {*}String $sealNo 印章编号 (32个字符)
     * @param {}float $scaling 图片缩放百分比 (介于0~1之间的数字)
     * @return {*}
     */
    public function modifySeal($account,$image,$isDefault=0,$sealName,$sealNo,$scaling){
        $this->url = '/user/modifySeal';
        $this->data = [
            'account'   => $account,
            'image'     => $image,
            'isDefault' => $isDefault,
            'sealName'  => $sealName,
            'sealNo'    => $sealNo,
            'scaling'   => $scaling,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: removeSeal
     * @description: 删除印章
     * @param {*}String $account 用户唯一识别码
     * @param {*}String $sealNo 印章编号
     * @return {*}
     */
    public function removeSeal($account,$sealNo){
        $this->url = '/user/removeSeal';
        $this->data = [
            'account' => $account,
            'sealNo'  => $sealNo,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: setDefaultSeal
     * @description: 设置默认章
     * @param {*}String $account 用户唯一识别码
     * @param {*}String $sealNo 印章编号如果为空，将把爱签系统生成的默认章重新设置为默认
     * @return {*}
     */
    public function setDefaultSeal($account,$sealNo){
        $this->url = '/user/setDefaultSeal';
        $this->data = [
            'account' => $account,
            'sealNo'  => $sealNo,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: getUserSeals
     * @description: 获取用户的印章列表
     * @param {*}String $account 唯一识别码
     * @return {*}
     */
    public function getUserSeals($account){
        $this->url = '/user/getUserSeals';
        $this->data = [
            'account' => $account,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: createLegalPersonSeal
     * @description: 创建法人章
     * @param {*}String $account 法人账号
     * @param {*}String $companyAccount 法人关联的企业账号
     * @return {*}
     */
    public function createLegalPersonSeal($account,$companyAccount){
        $this->url = '/user/createLegalPersonSeal';
        $this->data = [
            'account'        => $account,
            'companyAccount' => $companyAccount,
        ];
        return $this->request();
    }
//---------------------------------------------------------------------------------------签署类型接口
//
//---------------------------------------------------------------------------------------
    /**
     * @author: Neupres·lin
     * @name: createContract
     * @description: 上传合同
     * @param {*}String $contractNo 合同ID
     * @param {*}String $contractName 合同名称
     * @param {*}String $validityTime 合同有效期天数
     * @param {*}int $signOrder 签约方式，1：无序签约 2：顺序签约（默认普通签约）
     * @param {}List{MultipartFile} $contractFiles 合同附件
     * @param {}List{Object} $templates 合同模板列表
     * templates 参数说明 {templateNo String 否 合同模板编号 contractNo String 否 合同编号 fillData map 否 合同模板填充数据map}
     * @param {}int $smsType 取值【1、2...】
     * @param {}int $readSeconds 强制阅读时间(s)
     * @param {}int $needAgree 同意协议开关(1: 是，0: 否)
     * @param {}String $watermarkStr 需要合同预览图片中添加水印文字
     * @param {}String $notifyUrl 合同签署完成后回调通知地址,返回【"ok"】表示接收回调通知成功 post参数：action(签署固定状态值：signCompleted)，contractNo(合同编号)，status(合同状态，参考查询合同状态接口)，signTime(合同签署完成时间)，timestamp(合同签署完成时间戳)，validityTime(合同过期时间)，sign(签名)sign=RSA.generateSHA1withRSASignature(上述参数的json字符串按照字母顺序排序)
     * @param {}String $redirectUrl 合同签署完成后同步回调地址
     * @return {*}
     */
    public function createContract($contractNo, $contractName, $validityTime,$signOrder,$templates,$readSeconds,$needAgree,$redirectUrl,$file) {
        $this->url = '/contract/createContract';
        $templates = $this->array_sort($templates,'fillData');
        $this->data = [
            'contractNo'    => $contractNo,
            'contractName'  => $contractName,
            'validityTime'  => $validityTime,
            'signOrder'     => $signOrder,
            'templates'     => $templates,
            'readSeconds'   => $readSeconds,
            'needAgree'     => $needAgree,
            'notifyUrl'     => Tools::getHost() . '/api/notifyurl',
            'userNotifyUrl'     => Tools::getHost() . '/api/usernotifyurl',
            'redirectUrl' => $redirectUrl

        ];
        return $this->requestFile($file, 'contractFiles');
    }

    public function cancellation($contractNo, $validityTime, $notifyUrl = '', $redirectUrl = '')
    {
        $this->url = '/contract/cancellation';
        $this->data = [
            'contractNo' => $contractNo,
            'validityTime' => $validityTime,
            'notifyUrl' => $notifyUrl,
            'redirectUrl' => $redirectUrl,
        ];
        return $this->request();
    }


    public function array_sort($arr) {
        if($arr){
            foreach ($arr as $k => $v) {
                if($k == 'fillData'){
                    ksort($arr[$k]);
                }
            }
        }
        return $arr;
    }


    /**
     * @author: Neupres·lin
     * @name: addSigner
     * @description: 发起签署合同
     * @param {*}String $contractNo 合同唯一编码 (40位之内)
     * @param {*}String $account 唯一识别码
     * @param {*}int $signType 签约方式 2-无感知签章 3-有感知签章
     * @param {}String $sealNo signType
     * @param {}String $noticeMobile 签约短信通知号码
     * @param {}String $noticeEmail 签约短信通知邮箱号
     * @param {}String $signOrder 使用顺序签约时签约顺序编号,无序签约都是1
     * @param {}String $validateType 1:短信验证码签约，2：签约密码签约，3：人脸识别签约，6：手写识别签名+短信签约，7：手写签名+短信签约，8：手写签名+人脸识别签约，9：手写识别签名+人脸识别签约
     * @param {}int $autoSwitch 默认自动切换，0：不切换
     * @param {}String $isNoticeComplete 合同全部签署完成后是否通知用户，0：否 1：是
     * @param {}String $needPwdSignH5 0：否(默认) 1：是 是否需要密码签署页
     * @param {}String $waterMark 0：否（默认） 1：是，是否添加日期水印（距离底部10px）的正中央位置
     * @param {*}List{Object} $signStrategyList 在合同附件中签约策略
     * signStrategyList参数说明 attachNo int 是 附件编号，合同上传的附件序号:1,2,3… signKey String 否 关键字签约必传 locationMode String 是 定位方式，2-坐标签章 3-关键字签 signPage int 否 签约页码:坐标签约必传 signX double 否 左上角为原点，离左边框的宽度与pdf当页宽度的比例（小数位2位）, 坐标签约必传 signY double 否 左上角为原点，离顶边框的高度与pdf当页高度的比例（小数位2位）, 坐标签约必传
     * @param {}List{Object} $signStrikeList 在合同附件中骑缝章策略（仅支持企业用户）
     * signStrikeList参数说明 attachNo int 是 附件编号，合同上传的附件序号:1,2,3… crossStyle int 是 骑缝类型1：上下各一半2：左右各一半3：上下骑缝4：左右骑缝5：左骑6：右骑缝 signPage String 是 签约页码:坐标签约必传 （不能超过合同总页数，例：1-3）
     * @return {*}
     */
    public function addSigner($data){
        $this->url = '/contract/addSigner';
        $this->data = $data;
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: getContractStatus
     * @description: 查询合同状态
     * @param {*}String $contractNo 合同编号
     * @return {*}
     */
    public function getContractStatus($contractNo){
        $this->url = '/contract/getContractStatus';
        $this->data = [
            'contractNo'       => $contractNo,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: getContract
     * @description: 查询合同信息
     * @param {*}String $contractNo 合同编号
     * @return {*}
     */
    public function getContractData($contractNo){
        $this->url = '/contract/getContract';
        $this->data = [
            'contractNo'       => $contractNo,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: downloadContract
     * @description: 下载合同
     * @param {*}String $contractNo 合同编号
     * @param {}String $outfile 文件本地路径（下载的文件，写到本地）
     * @param {}int $downloadFileType 合同文件类型（多附件下载 1：pdf文件, 2：多个单张png文件（含pdf文件，单附件对应单张图片）, 3：分页png压缩文件 （含pdf文件）, 4：合同单张图片（不含pdf文件）, 5：所有的分页图片（不含pdf文件））
     * @return {*}
     */
    public function downloadContract($contractNo,$outfile,$downloadFileType){
        $this->url = '/contract/downloadContract';
        $this->data = [
            'contractNo'       => $contractNo,
            'outfile'          => $outfile,
            'downloadFileType' => $downloadFileType,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: uploadTemplate
     * @description: 上传模板
     * @param {*}String $templateName 模板名称
     * @param {*}String $templateNo 模板编号
     * @param {*}MultipartFile $templateFile 模板文件
     * @return {*}
     */
    public function uploadTemplate($templateName,$templateNo,$templateFile){
        $this->url = '/contract/uploadTemplate';
        $this->data = [
            'templateName' => $templateName,
            'templateNo'   => $templateNo,
            'templateFile' => $templateFile,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: downloadTemplate
     * @description: 下载模板
     * @param {*}String $templateNo 模板编号
     * @param {}String $outfile 文件本地路径（下载的文件，写到本地）
     * @return {*}
     */
    public function downloadTemplate($templateNo,$outfile){
        $this->url = '/contract/downloadTemplate';
        $this->data = [
            "templateNo" => $templateNo,
            "outfile" => $outfile,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: previewContract
     * @description: 预览合同
     * @param {*}String $contractNo 合同唯一编码 (40位之内)
     * @param {*}String $account 唯一识别码
     * @param {}int $isWrite 是否手写章（个人用户必传）1：是，0：否
     * @param {*}List{Object} $signStrategyList 在合同附件中签约策略
     * signStrategyList 参数说明 attachNo int 是 附件编号，合同上传的附件序号:1,2,3… locationMode String 是 定位方式，2-坐标签章（仅支持坐标） signPage int 是 签约页码:坐标签约必传 signX double 是 左上角为原点，离左边框的宽度与pdf当页宽度的比例（小数位2位）, 坐标签约必传 signY double 是 左上角为原点，离顶边框的高度与pdf当页高度的比例（小数位2位）, 坐标签约必传
     * @return {*}
     */
    public function previewContract($contractNo,$account,$isWrite=1){
        $this->url = '/contract/previewContract';
        $this->data = [
            [
                'contractNo'       => $contractNo,
                'account'          => $account,
                'isWrite'          => $isWrite,
                'signStrategyList' => []
            ]
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: passSign
     * @description: 密码签署合同
     * @param {*}String $contractNo 合同唯一编码 (40位之内)
     * @param {*}String $account 唯一识别码
     * @param {*}String $signPwd 签署密码
     * @return {*}
     */
    public function passSign($contractNo,$account,$signPwd){
        $this->url = '/contract/passSign';
        $this->data = [
            'contractNo' => $contractNo,
            'account'    => $account,
            'signPwd'    => $signPwd,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: downloadWithCert
     * @description: 下载存证证书
     * @param {} $contractNo 合同编号（合同编号与存证编号不能同时为空）
     * @param {} $preserveNo 存证编号（合同编号与存证编号不能同时为空）
     * @param {} $outfile 文件本地路径（下载的文件，写到本地）
     * @return {*}
     */
    public function downloadWithCert($contractNo,$preserveNo,$outfile){
        $this->url = '/contract/downloadWithCert';
        $this->data = [
            'contractNo' => $contractNo,
            'preserveNo' => $preserveNo,
            'outfile'    => $outfile,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: saveEvidence
     * @description: 合同存证
     * @param {*}String $contractNo 合同编号
     * @return {*}
     */
    public function saveEvidence($contractNo){
        $this->url = '/contract/saveEvidence';
        $this->data = [
            'contractNo' => $contractNo,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name:
     * @description:
     * @param {*}String $contractNo 合同唯一编码 (40位之内)
     * @param {*}String $account 唯一识别码
     * @param {*}int $signType 签约方式 2-无感知签章 3-有感知签章
     * @param {}String $sealNo 印章编号（32位之内）
     * @param {}String $noticeMobile 签约短信通知号码
     * @param {}String $noticeEmail 签约短信通知邮箱号
     * @param {}String $signOrder 使用顺序签约时签约顺序编号,无序签约都是1
     * @param {}String $validateType 1:短信验证码签约，2：签约密码签约，3：人脸识别签约，6：手写识别签名+短信签约，7：手写签名+短信签约，8：手写签名+人脸识别签约
     * @param {}String $isNoticeComplete 合同全部签署完成后是否通知用户，0：否 1：是
     * @param {}Integer $unions 空：否(默认普通签署策略) 1：为会签策略
     * @param {}Integer $lineNum 当为union为1时（会签），指定每行盖章的个数
     * @param {}Integer $lineSpace 当为union为1时（会签），指定每行盖章之间的间距(毫米)
     * @param {*}List{Object} $signStrategyList 在合同附件中签约策略
     * signStrategyList 参数说明 attachNo int 是 附件编号，合同上传的附件序号:1,2,3… locationMode String 是 定位方式，2-坐标签章（仅支持坐标） signPage int 是 签约页码:坐标签约必传 signX double 是 左上角为原点，离左边框的宽度与pdf当页宽度的比例（小数位2位）, 坐标签约必传 signY double 是 左上角为原点，离顶边框的高度与pdf当页高度的比例（小数位2位）, 坐标签约必传
     * @return {*}
     */
    public function addUnionSigner($contractNo,$account,$signType,$sealNo,$noticeMobile,$noticeEmail,$signOrder,$validateType,$isNoticeComplete,$unions,$lineNum,$lineSpace,$signStrategyList){
        $this->url = '/contract/addUnionSigner';
        $this->data = [
            'contractNo'       => $contractNo,
            'account'          => $account,
            'signType'         => $signType,
            'sealNo'           => $sealNo,
            'noticeMobile'     => $noticeMobile,
            'noticeEmail'      => $noticeEmail,
            'signOrder'        => $signOrder,
            'validateType'     => $validateType,
            'isNoticeComplete' => $isNoticeComplete,
            'unions'           => $unions,
            'lineNum'          => $lineNum,
            'lineSpace'        => $lineSpace,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: downloadByAttachName
     * @description: 下载合同（根据附件名）
     * @param {*}String $contractNo 合同编号
     * @param {*}List < String > $attachNames 附件名
     * @param {}String $outfile 文件本地路径（下载的文件，写到本地）
     * @param {}int $downloadFileType 合同文件类型（多附件下载 1：pdf文件, 2：多个单张png文件（含pdf文件，单附件对应单张图片）, 3：分页png压缩文件 （含pdf文件）, 4：合同单张图片（不含pdf文件）, 5：所有的分页图片（不含pdf文件））
     * @return {*}
     */
    public function downloadByAttachName($contractNo,$attachNames,$outfile,$downloadFileType){
        $this->url = '/contract/downloadByAttachName';
        $this->data = [
            'contractNo'       => $contractNo,
            'attachNames'      => $attachNames,
            'outfile'          => $outfile,
            'downloadFileType' => $downloadFileType,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: downloadChainReport
     * @description: 下载区块链存证报告
     * @param {*}String $contractNo 合同编号
     * @return {*}
     */
    public function downloadChainReport($contractNo){
        $this->url = '/contract/downloadChainReport';
        $this->data = [
            'contractNo' => $contractNo,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: identify
     * @description: 个人实名认证
     * @param {*}String $name 姓名
     * @param {*}String $idCard 身份证号码
     * @param {}String $mobile 手机号码
     * @param {}String $bankCard 银行卡号
     * @param {*}String $identifyType 实名认证类型 2：运营商三要素实名 3：银行卡四要素实名
     * @return {*}
     */
    public function identify($name,$idCard,$mobile,$bankCard,$identifyType){
        $this->url = '/user/identify';
        $this->data = [
            'name'         => $name,
            'idCard'       => $idCard,
            'mobile'       => $mobile,
            'bankCard'     => $bankCard,
            'identifyType' => $identifyType,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: enterpriseIdentify
     * @description: 企业实名认证
     * @param {*}String $companyName 公司名
     * @param {*}String $creditCode 企业社会统一信用代码
     * @param {*}String $name 法定代表人姓名
     * @param {*}String $idCard 法定代表人身份证
     * @param {}String $notifyUrl 实名认证结果回调通知url
     * @param {}String $identifyMobile 运营商认证填写运营商处登记的手机号，银行卡认证填写银行开卡时预留手机号
     * @param {}String $bankCard 银行卡号(银联卡)
     * @param {}String $code 银行卡号(银联卡)
     * @param {*}String $identifyType 实名认证类型 1：法人银行卡四要素认证 3：法人运营商三要素 4：法人人脸识别（此时notifyUrl参数为必传,回传参数请参考以下的/user/face接口的跳转说明）
     * @return {*}
     */
    public function enterpriseIdentify($companyName,$creditCode,$name,$idCard,$notifyUrl,$identifyMobile,$bankCard,$code,$identifyType){
        $this->url = '/user/enterpriseIdentify';
        $this->data = [
            'companyName'    => $companyName,
            'creditCode'     => $creditCode,
            'name'           => $name,
            'idCard'         => $idCard,
            'notifyUrl'      => $notifyUrl,
            'identifyMobile' => $identifyMobile,
            'bankCard'       => $bankCard,
            'code'           => $code,
            'identifyType'   => $identifyType,

        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: sendVerifyCode
     * @description: sendVerifyCode
     * @param {*}String $mobile 手机号
     * @return {*}
     */
    public function sendVerifyCode($mobile){
        $this->url = '/user/sendVerifyCode';
        $this->data = [
            'mobile' => $mobile,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: face
     * @description: 人脸活体认证
     * @param {*}String $name 姓名
     * @param {*}String $idCard 身份证号码
     * @param {*}String $notifyUrl 实名认证结果回调通知url
     * @return {*}
     */
    public function face($name,$idCard,$notifyUrl){
        $this->url = '/user/face';
        $this->data = [
            'name'      => $name,
            'idCard'    => $idCard,
            'notifyUrl' => $notifyUrl,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: identifyH5
     * @description: 个人实名认证H5
     * @param {}String $name 姓名（需要二要素校验时必传）
     * @param {}String $idCard 身份证号码（需要二要素校验时必传）
     * @param {*}Integer $identifyType 实名认证类型 2：运营商三要素实名 3：银行卡四要素实名4，人脸
     * @param {*}Integer $needIdentifyTwo 是否需要二要素校验（1:是；0:否）
     * @param {}String $notifyUrl 回调地址
     * @return {*}
     */
    public function identifyH5($name,$idCard,$identifyType,$needIdentifyTwo,$notifyUrl){
        $this->url = '/user/identifyH5';
        $this->data = [
            'name'            => $name,
            'idCard'          => $idCard,
            'identifyType'    => $identifyType,
            'needIdentifyTwo' => $needIdentifyTwo,
            'notifyUrl'       => $notifyUrl,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: faceCompare
     * @description: 人脸照片比对
     * @param {*}String $name 姓名
     * @param {*}String $idCard 身份证号码
     * @param {}String $url 照片地址（url 和 image 2个必选一个）
     * @param {}String $image base64的图片内容（url 和 image 2个必选一个）
     * @return {*}
     */
    public function faceCompare($name,$idCard,$url,$image){
        $this->url = '/user/faceCompare';
        $this->data = [
            'name'   => $name,
            'idCard' => $idCard,
            'url'    => $url,
            'image'  => $image,
        ];
        return $this->request();
    }
    /**
     * @author: Neupres·lin
     * @name: ocr
     * @description: ocr身份证识别
     * @param {*}MultipartFile $image 图片信息
     * @param {*}String $side front（正面）、back（反面）
     * @return {*}
     */
    public function ocr($image,$side){
        $this->url = '/user/ocr';
        $this->data = [
            'side'  => $side,
        ];
        return $this->requestFile($image);
    }

    /**
     * @author: Neupres·lin
     * @name: request
     * @description: api请求封装 函数步骤 对参数排序->生成签名->使用phpcurl发送带签名的请求->处理返回
     * @param {*}
     * @return {*}
     */
    protected function request() {

        //对参数进行排序
        ksort($this->data);
        foreach ($this->data as $key => $item) {
            if (is_array($item)) {
                ksort($item);
                $this->data[$key] = $item;
                foreach ($item as $k => $v) {
                    if (is_array($v)) {
                        ksort($v);
                        $this->data[$key][$k] = $v;
                    }
                }
            }
        }
//        print_r($this->data);
        //生成请求头的签名
        $time = self::msectime() + 600 * 1000;
        $signStr = json_encode($this->data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . md5(json_encode($this->data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)) . $this->appId . $time;
        $sign = self::sign($signStr, $this->apiSecret);

        $http = new GuzzleHttp\Client();
        $response = $http->request('POST', $this->domian . $this->url, [
            'headers' => ['sign' => $sign, 'Content-Type' => 'application/x-www-form-urlencoded'],
            'form_params' => [
                'bizData' => json_encode($this->data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
                'appId' => $this->appId,
                'timestamp' => $time,
            ]
        ]);

        $resData = json_decode($response->getBody()->getContents(),true);
        if (empty($resData) || $resData['code'] != '100000') {
            //报错
            $res = [
                'rt'   => false,
                'data' => $resData,
            ];
        } else {
//            if (isset($resData['data']['data'])) {
//                if (!file_exists('C:\Users\Administrator\Downloads')) {
//                    mkdir('C:\Users\Administrator\Downloads');
//                }
//                $resData['data']['pwd'] = 'C:\Users\Administrator\Downloads' . $resData['data']['fileName'];
//                $fp = fopen($resData['data']['pwd'], 'w');
//                fwrite($fp, base64_decode($resData['data']['data']));
//                fclose($fp);
//            }
            $res = [
                'rt'   => true,
                'data' => $resData['data'],
            ];


        }
        return $res;
    }

    /**
     * 去掉空值的key。
     *
     * @param $obj
     * @return array
     */
    public function filterEmpty($data) {
        $obj = $data;
        // 是数组
        if(is_array($obj)) {
            ksort($obj);
            foreach ($obj as $k => $v) {
                if(is_object($obj[$k]) || is_array($obj[$k])){
                    $obj[$k]= $this->filterEmpty($obj[$k]);
                }else {
                    if($v === null) {
                        unset($obj[$k]);
                    }
                }
            }
        }else {
            foreach ($obj as $k => $v) {
                if(is_object($obj->$k) || is_array($obj->$k)){
                    $obj->$k = $this->filterEmpty($obj->$k);
                }else if(!$v) {
                    unset($obj->$k);
                }
            }
        }

        return $obj;
    }

    /**
     * @author: Neupres·lin
     * @name: requestFile
     * @description: 带自定义pdf合同的请求 需要的参数有contractFiles路径 contractName pdf文件名
     * @param {*}
     * @return {*}
     */
    protected function requestFile($filePath, $paramkey) {
        ksort($this->data);
        // 去掉空值key
        $this->data = $this->filterEmpty($this->data);
        //对参数进行排序
//        $this->sortField();
        $this->data = json_encode($this->data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
//        var_dump($this->data);
        $time    = $this->msectime() + 600 * 1000;
        $signStr = $this->data . md5($this->data) . $this->appId . $time;
        $sign    = $this->sign($signStr, $this->apiSecret);
        $headers    = [
            "sign:" . $sign,
            "Content-Type:multipart/form-data;",
        ];

        if($filePath){
            $fileArr = new CURLFile(realpath($filePath),pathinfo($filePath)['extension'],basename($filePath));
        }else{
            $fileArr = '';
        }

        $postFields = ['bizData' => $this->data, 'appId' => $this->appId, 'timestamp' => $time, $paramkey => $fileArr];
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $this->domian.$this->url);
        curl_setopt($curl, CURLOPT_HEADER, 0);
        curl_setopt($curl, CURLOPT_POST, 1);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $postFields);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
//        // 生成分隔符
//        $delimiter = '-------------' . uniqid();
//
//        // 需要上传的文件数组
//        $fileFields = array(
//            'file' => array(
//                'name' => 'test',
//                'type' => "pdf",
//                'content' => file_get_contents($filePath)
//            ),
//        );
//
//        $data = '';
//        // 先将post的普通数据生成主体字符串
//        $postFields = ['bizData' => $this->data, 'appId' => $this->appId, 'timestamp' => $time];
//        foreach ($postFields as $name => $content) {
//            $data .= "--" . $delimiter . "\r\n";
//            $data .= 'Content-Disposition: form-data; name="' . $name . '"';
//            $data .= "\r\n\r\n" . $content . "\r\n";
//        }
//
//        // 将上传的文件生成主体字符串
//        foreach ($fileFields as $name => $file) {
//            $data .= "--" . $delimiter . "\r\n";
//            $data .= 'Content-Disposition: form-data; name="' . $paramkey . '"; filename="' . $file['name'] . "\" \r\n";
//            $data .= 'Content-Type: ' . $file['type'] . "\r\n\r\n";
//            $data .= $file['content'] . "\r\n";
//        }
//        // 主体结束的分隔符
//        $data .= "--" . $delimiter . "--";
//
//        $curl = curl_init();
//        curl_setopt($curl, CURLOPT_URL, $this->domian.$this->url);
//        curl_setopt($curl, CURLOPT_HEADER, 0);
//        curl_setopt($curl, CURLOPT_POST, 1);
//        curl_setopt($curl, CURLOPT_POSTFIELDS, $postFields);
//        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
//        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
//        curl_setopt($curl, CURLOPT_HTTPHEADER, array(
//                'Content-Type: multipart/form-data; boundary=' . $delimiter,
//                'Content-Length: ' . strlen($data).";sign" . $sign)
//        );

        $resData = curl_exec($curl);
//        echo PHP_EOL .$resData;
        $resData = json_decode($resData, true);
        if (empty($resData) || $resData['code'] != '100000') {
            $res = [
                'rt'   => false,
                'data' => $resData,
            ];
        } else {
            $res = [
                'rt'   => true,
                'data' => $resData['data'],
            ];
        }
        return $res;
    }
    /**
     * @author: Neupres·lin
     * @name: 工具箱
     * @description: 包含接口常用工具
     * @param {*}
     * @return {*}
     */
    //时间戳protected
    public static function msectime()
    {
        list($msec, $sec) = explode(' ', microtime());
        $msectime = (float) sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);
        return $msectime;
    }
    //ras非对称加密
    protected function sign($signString, $priKey)
    {
        $priKey = "-----BEGIN PRIVATE KEY-----\n" .
            wordwrap($priKey, 64, "\n", true) .
            "\n-----END PRIVATE KEY-----";
        $privKeyId = openssl_pkey_get_private($priKey);
        $signature = '';
        openssl_sign($signString, $signature, $privKeyId);
        openssl_free_key($privKeyId);
        return base64_encode($signature);
    }
    //ras验证
    protected function verify($data, $signString, $pubKey)
    {
        $pubKey = "-----BEGIN PUBLIC KEY-----\n" .
            wordwrap($pubKey, 64, "\n", true) .
            "\n-----END PUBLIC KEY-----";
        $pubKey = openssl_pkey_get_public($pubKey);
        $result = (bool) openssl_verify($data, base64_decode($signString), $pubKey);
        openssl_free_key($pubKey);
        return $result;
    }

}
